package manager

import (
	"net/http"

	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/spf13/cast"
)

type ManagerController struct {
	manager *TaskManagerService
}

func NewManagerController() *ManagerController {

	return &ManagerController{manager: manager}
}

func (controller *ManagerController) GetTaskDetail(c *gin.Context) {

	req := &GetTaskDetailReq{}
	if err := c.ShouldBind(&req); err != nil {
		_ = c.Error(err).
			SetType(gin.ErrorTypePublic)
		return
	}

	resp, err := controller.manager.Stats(req.TaskID)
	if err != nil {
		_ = c.Error(err).
			SetType(gin.ErrorTypePublic)
		return
	}

	c.JSON(http.StatusOK, &Response{Result: resp, Message: SUCCESS})
}

func (controller *ManagerController) GetTaskResult(c *gin.Context) {

	req := &GetTaskDetailReq{}
	if err := c.ShouldBind(&req); err != nil {
		_ = c.Error(err).
			SetType(gin.ErrorTypePublic)
		return
	}

	resp, err := controller.manager.Download(req.TaskID)
	if err != nil {
		c.JSON(http.StatusBadRequest, Response{
			Code:    ERROR,
			Message: err.Error(),
		})
		return
	}

	c.File(resp)
}

func (controller *ManagerController) GetTaskList(c *gin.Context) {

	req := &GetTaskListReq{}
	if err := c.ShouldBind(&req); err != nil {
		_ = c.Error(err).
			SetType(gin.ErrorTypePublic)
		return
	}

	resp, err := controller.manager.GetTaskList(req.State, req.pNo, req.pSize, req.Detail)
	if err != nil {
		_ = c.Error(err).
			SetType(gin.ErrorTypePublic)
		return
	}

	c.JSON(http.StatusOK, &Response{Result: resp, Message: SUCCESS})
}

func (controller *ManagerController) Create(c *gin.Context) {

	req := &CreateReq{}
	if err := c.ShouldBindWith(&req, binding.Form); err != nil {
		_ = c.Error(err).
			SetType(gin.ErrorTypePublic)
		return
	}

	var (
		err       error
		fCallBack func(dst string) error
	)

	if req.UploadType == uploadTypeFormFile {
		if _, ok := c.Request.MultipartForm.File["file"]; ok {

			fCallBack = func(dst string) error {

				fh, _ := c.FormFile("file")
				return c.SaveUploadedFile(fh, dst)
			}
		} else {
			c.JSON(http.StatusOK, &Response{Message: "文件不存在"})
			return
		}
	}

	resp, err := controller.manager.Create(req, fCallBack)
	if err != nil {
		_ = c.Error(err).
			SetType(gin.ErrorTypePublic)
		return
	}

	c.JSON(http.StatusOK, &Response{Result: resp, Message: SUCCESS})
}

func (controller *ManagerController) Settings(c *gin.Context) {

	req := SettingsReq{}
	if err := c.ShouldBindWith(&req, binding.Form); err != nil {
		_ = c.Error(err).
			SetType(gin.ErrorTypePublic)
		return
	}

	var (
		err    error
		result interface{}
	)

	for key, value := range req {
		switch key {
		case "concurrency": // 控制同时执行的任务的数量
			controller.manager.SetConcurrency(cast.ToInt(value))
			break
		case "fetch_count_on_time": // 控制同时执行的任务的数量
			controller.manager.SetConcurrency(cast.ToInt(value))
			break
		}
	}

	if err != nil {
		c.JSON(http.StatusBadRequest, Response{
			Code:    ERROR,
			Message: err.Error(),
		})
		return
	}

	c.JSON(http.StatusOK, &Response{Result: result, Message: SUCCESS})
}

func (controller *ManagerController) Control(c *gin.Context) {

	req := &ControlReq{}
	if err := c.ShouldBindWith(&req, binding.Form); err != nil {
		_ = c.Error(err).
			SetType(gin.ErrorTypePublic)
		return
	}

	var (
		err    error
		result interface{}
	)
	switch req.Op {
	case "start":
		err = controller.manager.Start(req.TaskID, true)
		break
	case "pause":
		err = controller.manager.Pause(req.TaskID)
		break
	case "terminate":
		err = controller.manager.Terminate(req.TaskID)
		break
	case "state":
		result, err = controller.manager.Stats(req.TaskID)
		break
	case "prioritise":
		err = controller.manager.AdjustPriority(req.FromID, req.ToID, req.BeforeOrAfter)
		break
	}

	if err != nil {
		c.JSON(http.StatusBadRequest, Response{
			Code:    ERROR,
			Message: err.Error(),
		})
		return
	}

	c.JSON(http.StatusOK, &Response{Result: result, Message: SUCCESS})
}

func (controller *ManagerController) GetClusterList(c *gin.Context) {

	req := GetClusterListReq{}
	if err := c.ShouldBind(&req); err != nil {
		_ = c.Error(err).
			SetType(gin.ErrorTypePublic)
		return
	}

	resp, err := controller.manager.GetClusterList(req)
	if err != nil {
		_ = c.Error(err).
			SetType(gin.ErrorTypePublic)
		return
	}

	c.JSON(http.StatusOK, &Response{Result: resp, Message: SUCCESS})
}
